﻿using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Cemit.PolyServer
{
    public static class MessageHandles
    {
        static Dictionary<Type, IMessageHandle> messagesHandlesPairs;

        static MessageHandles()
        {
            IEnumerable<Type> types = AppDomain.CurrentDomain
                .GetAssemblies()
                .SelectMany(SelectMessageHandle);

            messagesHandlesPairs = new Dictionary<Type, IMessageHandle>();
            foreach (var type in types)
            {
                foreach (var item in type.GetInterfaces().Where(IsMessageHandleType))
                {
                    messagesHandlesPairs.Add(
                        item.GetGenericArguments()[0], CreateMessageHandleInstance(type));
                    //Console.WriteLine($"add:{item.GetGenericArguments()[0].Name} {type.Name}");
                }
            }

            IMessageHandle CreateMessageHandleInstance(Type messageHandleType)
                => (IMessageHandle)messageHandleType.Assembly
                    .CreateInstance(messageHandleType.FullName);

            IEnumerable<Type> SelectMessageHandle(Assembly a)
                => a.GetTypes().Where(
                        t => t.GetInterfaces()
                            .Any(IsMessageHandleType));

            bool IsMessageHandleType(Type type)
                => type.IsGenericType
                    && type.GetGenericTypeDefinition() == typeof(IMessageHandle<>);
        }

        public static IMessageHandle GetHandle(Type messageType)
        {
            if (!messagesHandlesPairs.ContainsKey(messageType))
            {
                return new NullHandle();
            }
            return messagesHandlesPairs[messageType];
        }

        public static IMessageHandle GetHandle(this IMessage message)
        {
            return GetHandle(message.GetType());
        }

        public static bool IsNull(this IMessageHandle message)
        {
            return message.GetType() == typeof(Nullable);
        }

    }
}
